﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YiDa.Infrastructure;
using YiDa.Domain.Events;
using System.Diagnostics;
using System.Collections.Generic;
using YiDa.Domain.Repositories;
using YiDa.Events.Bus;

namespace YiDa.Domain.Test
{
    [TestClass]
    public class EventTest
    {
        [TestMethod]
        public void TestEvent()
        {
            //var o = ServiceLocator.Instance.GetService<IMockEntityRespository>();
            //Assert.IsNotNull(o);
            var app = ServiceLocator.Instance.GetService<IMockApplication>();
            app.Begin();
        }
    }

    public class MockEntity:AggregateRoot
    {
        public void Confirm()
        {
            RaiseEvent<MockEvent>(new MockEvent(this));
        }
    }

    public class MockEvent:DomainEvent
    {
        public MockEvent(IEntity source) : base(source) { }
    }

    public class MockDomainEventHandler:DomainEventHandler<MockEvent>
    {
        public override void Handle(MockEvent evnt)
        {
            Debug.WriteLine("MockDomainEventHandler Handled");
        }
    }

    public class MockEventHandler : YiDa.Events.Handlers.EventHandler<MockEvent>
    {
        public override void Handle(MockEvent evnt)
        {
            Debug.WriteLine("MockEventHandler Handled");
        }
    }
    
    public interface IMockApplication:IApplicationServiceContract
    {
        void Begin();
    }

    public class MockApplicationImpl : DisposableObject,IMockApplication
    {
        private readonly List<IDomainEventHandler<MockEvent>> handlers = new List<IDomainEventHandler<MockEvent>>();
        private readonly IMockEntityRespository repository = null;
        private readonly IRepositoryContext context = null;

        private readonly Action<MockEvent> orderConfirmedEventHandlerAction2 = t =>
        {
            Debug.WriteLine("MockApplicationImpl MockEventHandler Handled");
        };

        public MockApplicationImpl(IRepositoryContext context, IMockEntityRespository repository, IDomainEventHandler<MockEvent>[] handlers)
        {
            this.context = context;
            this.repository = repository;

            this.handlers.AddRange(handlers);
            foreach (var handler in this.handlers)
            {
                DomainEventAggregator.Subscribe<MockEvent>(handler);            //定义领域事件处理器，通过IOC注入进来的
            }


            DomainEventAggregator.Subscribe<MockEvent>(orderConfirmedEventHandlerAction2);
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (var handler in this.handlers)
                    DomainEventAggregator.Unsubscribe<MockEvent>(handler);

                DomainEventAggregator.Unsubscribe<MockEvent>(orderConfirmedEventHandlerAction2);
            }
        }

        public void Begin()
        {
            var en = new MockEntity();
            en.Confirm();
            repository.Add(en);            
            context.Commit();
        }
    }

    public class MockRespositoryContext:RepositoryContext
    {
        public MockRespositoryContext(IBus bus) : base(bus) { }

        public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
        {
            this.DumpPendingEvents(obj);
        }

        public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
        {
            this.DumpPendingEvents(obj);
        }

        public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
        {
            this.DumpPendingEvents(obj);
        }

        protected override void DoCommit()
        {
            //
        }

        public override void Rollback()
        {
            //
        }
    }

    public class MockRespository<T> : Repository<T> where T : class, IAggregateRoot
    {
        private readonly MockRespositoryContext efContext;

        public MockRespository(IRepositoryContext context)
            : base(context)
        {
            if (context is MockRespositoryContext)
                this.efContext = context as MockRespositoryContext;
        }

        protected override void DoAdd(T aggregateRoot)
        {
            efContext.RegisterNew<T>(aggregateRoot);
        }

        protected override void DoRemove(T aggregateRoot)
        {
            efContext.RegisterDeleted<T>(aggregateRoot);
        }

        protected override void DoUpdate(T aggregateRoot)
        {
            efContext.RegisterModified<T>(aggregateRoot);
        }

        protected override T DoGetByKey(Guid key)
        {
            throw new NotImplementedException();
        }

        protected override IEnumerable<T> DoGetAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder)
        {
            throw new NotImplementedException();
        }

        protected override IEnumerable<T> DoGetAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override PagedResult<T> DoGetAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize)
        {
            throw new NotImplementedException();
        }

        protected override PagedResult<T> DoGetAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override IEnumerable<T> DoFindAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder)
        {
            throw new NotImplementedException();
        }

        protected override PagedResult<T> DoFindAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize)
        {
            throw new NotImplementedException();
        }

        protected override IEnumerable<T> DoFindAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override PagedResult<T> DoFindAll(Specifications.ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override T DoGet(Specifications.ISpecification<T> specification)
        {
            throw new NotImplementedException();
        }

        protected override T DoFind(Specifications.ISpecification<T> specification)
        {
            throw new NotImplementedException();
        }

        protected override T DoGet(Specifications.ISpecification<T> specification, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override T DoFind(Specifications.ISpecification<T> specification, params System.Linq.Expressions.Expression<Func<T, dynamic>>[] eagerLoadingProperties)
        {
            throw new NotImplementedException();
        }

        protected override bool DoExists(Specifications.ISpecification<T> specification)
        {
            throw new NotImplementedException();
        }
    }

    public interface IMockEntityRespository: IRepository<MockEntity>
    {

    }

    public class MockEntityRespository : MockRespository<MockEntity>, IMockEntityRespository
    {
        public MockEntityRespository(IRepositoryContext context)
            : base(context)
        { }
    }
}
